/*
 * CSim.java
 *
 * Copyright (c) 2009 Giles Millward (Manigra). All rights reserved.
 *
 * This file is part of JRogueDPS.
 *
 * JRogueDPS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JRogueDPS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JRogueDPS.  If not, see <http://www.gnu.org/licenses/>.
 */
package dpssystem;

import dpsinterface.CDPSInterface;
import dpsinterface.CDPSWeapon;
import dpsstats.CAllStats;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

/**
 *
 * @author Mani
 */
public class CSim extends Thread {

    public CPlayer m_player;
    public CAttackChance m_attackChance;
    public CDPSInterface m_dpsInterface;
    public CBaseStats m_baseStats;
    public CAllStats m_stats;
    public CProcManager m_trinketManager;
    public CGlobalCooldown m_gcd;
    public CArmorPenReduction m_arpReduction;
    public CMutilate m_mutilate;
    public CSinisterStrike m_sinisterStrike;
    public CTarget m_target;
    public CHaste m_haste;
    public CEnvenom m_envenom;
    public CEviscerate m_eviscerate;
    public CRupture m_rupture;
    public CAI m_ai;
    public CStubAbility m_stubAbility;

    public double m_currentRunTime = 0.0;
    public double m_maxRunTime;
    int m_threadNumber;

    ArrayList<CEvent> m_eventList = new ArrayList<CEvent>();
    Random m_rng;

    CSim(CDPSInterface p_dpsInterface, double p_maxRunTime, int p_threadNumber) {        
        m_rng = new Random();
        m_maxRunTime = p_maxRunTime;
        m_threadNumber = p_threadNumber;
        m_dpsInterface = p_dpsInterface;
        m_attackChance = new CAttackChance(this, m_rng);
        m_stats = new CAllStats(p_maxRunTime); // Stats container for this run
        m_baseStats = new CBaseStats(m_dpsInterface);
        m_trinketManager = new CProcManager(this);
        m_arpReduction = new CArmorPenReduction(this);
        m_gcd = new CGlobalCooldown(this);
        m_target = new CTarget(this);
        m_haste = new CHaste(this);
        m_ai = new CAI(this);
        // TODO Remove dummy ability when completed
        m_stubAbility = new CStubAbility(this);
        
        // Create our weapons
        CDPSWeapon l_weapon = m_dpsInterface.m_MHWeapon;
        CWeapon l_MHWeapon = new CWeapon(
                "MH " + l_weapon.getName() + " (" +
                l_weapon.getWeaponType().toString() + ")",
                l_weapon.getMinDamage(),
                l_weapon.getMaxDamage(),
                l_weapon.getWeaponSpeed(),
                l_weapon.getModifier(),
                l_weapon.getPoisonType(),
                l_weapon.getWeaponType(),
                m_stats.m_MHAutoAttack,
                m_stats.m_MHPoisonStats,
                true,
                l_weapon.getProcItem(),
                this);

        l_weapon = m_dpsInterface.m_OHWeapon;
        CWeapon l_OHWeapon = new CWeapon(
                "OH " + l_weapon.getName() + " (" +
                l_weapon.getWeaponType().toString() + ")",
                l_weapon.getMinDamage(),
                l_weapon.getMaxDamage(),
                l_weapon.getWeaponSpeed(),
                l_weapon.getModifier(),
                l_weapon.getPoisonType(),
                l_weapon.getWeaponType(),
                m_stats.m_OHAutoAttack,
                m_stats.m_OHPoisonStats,
                false,
                l_weapon.getProcItem(),
                this);

        // Allow a weapon to reference the handed weapon
        l_MHWeapon.setOtherWeapon(l_OHWeapon);
        l_OHWeapon.setOtherWeapon(l_MHWeapon);

        m_player = new CPlayer(this, "Player", l_MHWeapon, l_OHWeapon);
        m_mutilate = new CMutilate(this);
        m_sinisterStrike = new CSinisterStrike(this);
        m_envenom = new CEnvenom(this);
        m_eviscerate = new CEviscerate(this);
        m_rupture = new CRupture(this);
    }

    @Override
    public void run() {
        m_ai.linkAbilities();
        m_eventList.add(new CAutoAttackEvent(0, this.m_player.m_MHWeapon));
        m_eventList.add(new CAutoAttackEvent(0, this.m_player.m_OHWeapon));

        // Start the energy regen for one energy every 0.1 seconds.
        this.m_player.m_energyRegen.startEnergyRegen();

        // Setup 'On Use' trinkets
        m_trinketManager.queueUpOnUseProcs(this);

        Collections.sort(m_eventList);

        while(m_eventList.size() > 0 &&
              (m_currentRunTime = m_eventList.get(0).getEventTime()) <= m_maxRunTime)
        {
            ArrayList<CEvent> l_list = m_eventList.get(0).runEvent(this);
            m_eventList.remove(0);
            if (l_list != null)
            {
                m_eventList.addAll(l_list);
            }

            // Sort in chronological order
            Collections.sort(m_eventList);
        }

        m_stats.calculateTotalDPS();
    }

    // Remove a specific type of class from the list
    public void removeEventClass(Class p_class)
    {
        for (int i = 0; i < m_eventList.size(); i++)
        {
            if (m_eventList.get(i).getClass() == p_class)
            {
                m_eventList.remove(i);
            }
        }
    }

    public void log(String p_string)
    {
        System.out.println(this.m_threadNumber + ": " + this.m_currentRunTime + ": " + p_string);
    }
}



